package org.leon;

import org.leon.pojo.Configuration;
import org.leon.pojo.SqlTypeEnum;

import java.lang.reflect.*;
import java.util.List;

/**
 * Created by leon.L on 2019/12/25.
 * Desc :
 */
public class DefaultSqlSession implements SqlSession {

    private Configuration configuration;
    private Executor executor;

    public DefaultSqlSession(Configuration configuration, Executor executor) {
        this.configuration = configuration;
        this.executor = executor;
    }

    /**
     * 查询列表
     *
     * @param sqlId
     * @param params
     * @return
     */
    @Override
    public <E> List<E> selectList(String sqlId, Object... params) throws Exception {
        List<Object> objectList = this.executor.query(configuration, configuration.getSqlMapper().get(sqlId), params);
        return (List<E>) objectList;
    }

    /**
     * 查询单条
     *
     * @param sqlId
     * @param params
     * @return
     */
    @Override
    public <T> T selectOne(String sqlId, Object... params) throws Exception{
        List<Object> objects = selectList(sqlId, params);
        if (objects.size() == 1) {
            return (T) objects.get(0);
        } else {
            throw new RuntimeException("Null or too many results");
        }
    }

    public int update(String statementId, Object parameter) throws Exception{
        int effectRows;
        try {
            effectRows = this.executor.update(this.configuration, configuration.getSqlMapper().get(statementId), parameter);
        } catch (Exception e) {
            throw e;
        }

        return effectRows;
    }

    public int insert(String statementId, Object parameter) throws Exception{
        return this.update(statementId, parameter);
    }

    public int delete(String statementId, Object parameter) throws Exception{
        return this.update(statementId, parameter);
    }

    @Override
    public <T> T getMapper(Class<?> mapperClass) {
        // 使用动态代理生成代理对象

        Object proxyInstance = Proxy.newProxyInstance(DefaultSqlSession.class.getClassLoader(), new Class[]{mapperClass}, new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                // 获取方法所在的mapper的名称
                String className = method.getDeclaringClass().getName();
                // 获取当前方法的名称
                String methodName = method.getName();

                // 拼接 sqlId
                String sqlId = className + "." + methodName;

                SqlTypeEnum sqlType = configuration.getSqlMapper().get(sqlId).getSqlType();
                switch (sqlType){
                    case DELETE:
                        return delete(sqlId, args[0]);    // 这种方式算是一种硬编码，参数数量为空会引起越界异常
                    case INSERT:
                        return insert(sqlId, args[0]);
                    case UPDATE:
                        return update(sqlId, args[0]);
                    default:
                        // 获取当前方法的返回值类型
                        Type genericReturnType = method.getGenericReturnType();

                        // 判断返回类型是不是一个泛型类型，如果是，则表明是一个集合类型
                        if (genericReturnType instanceof ParameterizedType) {
                            return selectList(sqlId, args);
                        } else {
                            return selectOne(sqlId, args);
                        }
                }
            }
        });
        return (T) proxyInstance;
    }
}
